package org.kisekiproject.evaluator.nodes {
	import flash.events.Event;
	import flash.events.EventDispatcher;
	
	import org.kisekiproject.evaluator.IFunction;
	import org.kisekiproject.evaluator.IVariableNamespace;

	/**
	 * Function call.
	 */
	public class FunctionNode extends EventDispatcher implements ISyntaxNode {

		private var _index:int;
		private var _name:String;
		private var _arguments:Array;
		private var _variables:IVariableNamespace;
		private var _function:IFunction;

		/**
		 * Constructor.
		 */
		public function FunctionNode(variables:IVariableNamespace, name:String, arguments:Array, index:int) {
			_index=index;
			_name=name;
			_arguments=arguments;
			_variables=variables;

			for each (var arg:ISyntaxNode in _arguments)
				arg.addEventListener(Event.CHANGE,onDependencyChange);
		}

		/**
		 * Dependency change.
		 */
		private function onDependencyChange(e:Event):void {
			dispatchEvent(new Event(Event.CHANGE));
		}

		/**
		 * Get value.
		 */
		public function get value():Object {
			if (_function)
				return _function.value;

			var f:Object=_variables.getVariable(_name);

			if (f is IFunction) {
				_function=IFunction(f);
				_function.arguments=argumentArray;
				_function.addEventListener(Event.CHANGE,onFunctionChange);
				return _function.value;
			}

			if (!(f is Function))
				throw new Error("Not a function: "+_name);

			return (f as Function).apply(null,argumentArray);
		}

		/**
		 * Function change.
		 */
		private function onFunctionChange(e:Event):void {
			dispatchEvent(new Event(Event.CHANGE));
		}

		/**
		 * Get arg array.
		 */
		private function get argumentArray():Array {
			var argValues:Array=new Array();

			for each (var arg:ISyntaxNode in _arguments)
				argValues.push(arg.value);

			return argValues;
		}

		/**
		 * Get stream index.
		 */
		public function get index():int {
			return _index;
		}
	}
}